package com.example.searchservice.service.impl;

import co.elastic.clients.elasticsearch.indices.AnalyzeRequest;
import com.example.searchservice.doc.UserDocument;
import com.example.searchservice.repository.UserRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;


import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import co.elastic.clients.elasticsearch._types.query_dsl.*;

import com.example.searchservice.repository.ElasticsearchQueryUtils;




@Service
@Slf4j
public class UserServiceImpl implements com.example.searchservice.service.UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    private final ObjectMapper objectMapper = new ObjectMapper();

    //jdk 17 虚拟线程池
    private static final ExecutorService vexecutor = Executors.newVirtualThreadPerTaskExecutor();

    /**
     * 创建或更新用户
     */
    public UserDocument saveUser(UserDocument user) {
        for(int i = 0; i < 10000; i++){
            int finalI = i;
            vexecutor.execute(() -> {
                user.setId(finalI + "");
                user.setName(user.getName());
                user.setNote(user.getNote());
                user.setAge( finalI);
                user.setCreatedAt(LocalDateTime.now());
                user.setUpdatedAt(LocalDateTime.now());
                userRepository.save(user);
            });
        }
        return userRepository.save(user);
    }




    @Override
    public Optional<UserDocument> findById(String id) {
        try {
            Query termQuery = ElasticsearchQueryUtils.buildTermQuery("id", id);
            NativeQuery searchQuery = NativeQuery.builder()
                    .withQuery(termQuery)
                    .build();

            SearchHits<UserDocument> searchHits = elasticsearchOperations.search(searchQuery, UserDocument.class);

            if (searchHits.isEmpty()) {
                return Optional.empty();
            }

            return Optional.of(searchHits.getSearchHit(0).getContent());
        } catch (Exception e) {
            log.error("根据ID查询用户文档失败: {}", id, e);
            throw new RuntimeException("查询用户文档失败", e);
        }

//        return userRepository.findById(id).orElse(null);
    }

    /**
     * 批量保存
     */
    public Iterable<UserDocument> saveAll(List<UserDocument> users) {
        return userRepository.saveAll(users);
    }

//    @PostConstruct
    public void createIndexWithAnalyzer() {
        try {
            // 删除现有索引（可选）
            if (elasticsearchOperations.indexOps(UserDocument.class).exists()) {
                elasticsearchOperations.indexOps(UserDocument.class).delete();
            }

            // 创建索引并配置分词器
            elasticsearchOperations.indexOps(UserDocument.class).createWithMapping();

        } catch (Exception e) {
            log.error("创建索引失败: " + e.getMessage(),e);
        }
    }

    /**
     * 搜索用户
     */
    public SearchHits<UserDocument> searchUsers(String query) {
        org.springframework.data.elasticsearch.core.query.Query searchQuery =  org.springframework.data.elasticsearch.core.query.Query.findAll();
        // 这里可以构建更复杂的查询
        SearchHits<UserDocument> users = elasticsearchOperations.search(searchQuery, UserDocument.class);
        log.info("SearchHits: " + users);
        return users;
    }

    /**
     * 获取索引信息
     */
    public Map<String, Object> getIndexInfo() {
        IndexOperations indexOps = elasticsearchOperations.indexOps(UserDocument.class);
        return Map.of(
                "exists", indexOps.exists(),
                "mapping", indexOps.getMapping(),
                "settings", indexOps.getSettings()
        );
    }

    /**
     * 创建索引（如果不存在）
     */
    public void createIndexIfNotExists() {
        IndexOperations indexOps = elasticsearchOperations.indexOps(UserDocument.class);
        if (!indexOps.exists()) {
            indexOps.create();
            indexOps.putMapping(indexOps.createMapping());
        }
    }

    // 基础分页
    public Page<UserDocument> getUserDocuments(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return userRepository.findAll(pageable);
    }

    // 带排序的分页
    public Page<UserDocument> getUserDocumentsSorted(int page, int size, String sortBy, String direction) {
        Sort sort = Sort.by(Sort.Direction.fromString(direction), sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);
        return userRepository.findAll(pageable);
    }

    // 条件分页
    public Page<UserDocument> searchUserDocuments(String keyword, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return userRepository.findByNameContaining(keyword, pageable);
    }

    // 多条件分页
    public Page<UserDocument> advancedSearch(String name, Double minPrice, Double maxPrice,
                                        int page, int size, String sortBy, String direction) {
        Sort sort = Sort.by(Sort.Direction.fromString(direction), sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        if (name != null) {
            return userRepository.findByNameContaining(name, pageable);
        } else if (minPrice != null && maxPrice != null) {
            return userRepository.findByNameContainingAndAgeBetween(name, minPrice, maxPrice, pageable);
        } else {
            return userRepository.findAll(pageable);
        }
    }

    // 1. 基础搜索
    public List<UserDocument> searchUserDocuments(String keyword) {
        Query query = ElasticsearchQueryUtils.buildMultiMatchQuery(keyword, "name", "note");

        NativeQuery searchQuery = new NativeQueryBuilder()
                .withQuery(query)
                .build();

        return executeSearch(searchQuery);
    }

    // 2. 分页搜索
    public Page<UserDocument> searchUserDocuments(String keyword, Pageable pageable) {
        Query query = ElasticsearchQueryUtils.buildMultiMatchQuery(keyword, "name", "note");

        NativeQuery searchQuery = new NativeQueryBuilder()
                .withQuery(query)
                .withPageable(pageable)
                .build();

        SearchHits<UserDocument> searchHits = elasticsearchOperations.search(searchQuery, UserDocument.class);
        List<UserDocument> UserDocuments = extractUserDocuments(searchHits);

        return new PageImpl<>(
                UserDocuments, pageable, searchHits.getTotalHits()
        );
    }

    // 3. 高级搜索
    public List<UserDocument> advancedSearch(String name, String category, Double minPrice, Double maxPrice) {
        // 构建各个查询条件
        Query matchQuery = ElasticsearchQueryUtils.buildMatchQuery("name", name);
        Query termQuery = ElasticsearchQueryUtils.buildTermQuery("category", category);
        Query rangeQuery = ElasticsearchQueryUtils.buildRangeQuery("price", minPrice, maxPrice);

        // 构建布尔查询
        Query boolQuery = ElasticsearchQueryUtils.buildBooFilterlQuery(
                Arrays.asList(matchQuery),
                Arrays.asList(termQuery, rangeQuery)
        );

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(boolQuery)
                .build();

        return executeSearch(searchQuery);
    }

    // 4. 模糊搜索
    public List<UserDocument> fuzzySearch(String name) {
        Query query = ElasticsearchQueryUtils.buildFuzzyQuery("name", name);

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(query)
                .build();

        return executeSearch(searchQuery);
    }

    // 5. 通配符搜索（性能较差，慎用）
    public List<UserDocument> wildcardSearch(String value) {
        Query query = ElasticsearchQueryUtils.buildContainsQuery("name", value);

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(query)
                .build();

        return executeSearch(searchQuery);
    }

    private List<UserDocument> executeSearch(NativeQuery searchQuery) {
        try {
            SearchHits<UserDocument> searchHits = elasticsearchOperations.search(
                    searchQuery,
                    UserDocument.class
            );

            return searchHits.stream()
                    .map(SearchHit::getContent)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            throw new RuntimeException("搜索执行失败", e);
        }
    }

    private List<UserDocument> extractUserDocuments(SearchHits<UserDocument> searchHits) {
        return searchHits.getSearchHits().stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }

    // 中文分词搜索
    public List<UserDocument> chineseFindByNameContaining(String name) {
        Query query = ElasticsearchQueryUtils.buildSmartMatchQuery("name", name);

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(query)
                .build();

        SearchHits<UserDocument> searchHits = elasticsearchOperations.search(searchQuery, UserDocument.class);

        return searchHits.getSearchHits().stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }

    public Page<UserDocument> chineseFindByNameDesc(String name,int page, int size) {
        Sort sort = Sort.by(Sort.Direction.ASC, "id");
        Pageable pageable = PageRequest.of(page, size);
//        Query query = ElasticsearchQueryUtils.buildNgramQuery("name", name);
//        Query query = ElasticsearchQueryUtils.buildMatchQuery("name", name);
        Query query = ElasticsearchQueryUtils.buildSmartMatchQuery("name", name);

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(query)
                .withPageable(pageable)
                .withSort(sort)
                .build();
        System.out.println("searchQuery: " + searchQuery.getQuery().toString());

        SearchHits<UserDocument> searchHits = elasticsearchOperations.search(searchQuery, UserDocument.class);
        List<UserDocument> UserDocuments = extractUserDocuments(searchHits);

        return new PageImpl<>(
                UserDocuments, pageable, searchHits.getTotalHits()
        );
    }

    // 中文模糊搜索
    public List<UserDocument> chinesePhraseFindByName(String name) {
        Query query = ElasticsearchQueryUtils.buildMatchPhraseQuery("name", name);

        NativeQuery searchQuery = NativeQuery.builder()
                .withQuery(query)
                .build();

        SearchHits<UserDocument> searchHits = elasticsearchOperations.search(searchQuery, UserDocument.class);

        return searchHits.getSearchHits().stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }

    /**
     * 检查IK分词器是否正常工作
     */
    public boolean testIkAnalyzer() {
        try {
            Query query = ElasticsearchQueryUtils.buildMatchQuery("name", "test");

            NativeQuery searchQuery = NativeQuery.builder()
                    .withQuery(query)
                    .build();

            elasticsearchOperations.search(searchQuery, UserDocument.class);
            return true;
        } catch (Exception e) {
            log.error("IK分词器测试失败", e);
            return false;
        }
    }

    public List<UserDocument> safeChineseSearch(String keyword) {
        try {
            if (keyword == null || keyword.trim().isEmpty()) {
                return Collections.emptyList();
            }
            Sort sort = Sort.by(Sort.Direction.DESC, "id");
            System.out.println("sort:" + sort.toString());
            Pageable pageable = PageRequest.of(0, 5, sort);

            NativeQuery searchQuery = NativeQuery.builder()
                    .withQuery(q -> q
                            .match(m -> m
                                    .field("name")
                                    .query(keyword.trim())
                                    .analyzer("ik_max_word")
                                    .operator(Operator.And)

                            )
                    )
                    .withPageable(pageable)
                    .build();

            System.out.println("searchQuery: " + searchQuery.getQuery().toString());
            SearchHits<UserDocument> searchHits = elasticsearchOperations.search(
                    searchQuery,
                    UserDocument.class
            );

            return searchHits.stream()
                    .map(SearchHit::getContent)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("中文搜索失败，关键词: {}", keyword, e);
            // 降级方案：使用简单查询
            return fallbackSearch(keyword);
        }
    }

    private List<UserDocument> fallbackSearch(String keyword) {
        try {
            // 使用标准匹配查询作为降级方案
            Criteria criteria = new Criteria("name").contains(keyword);
            org.springframework.data.elasticsearch.core.query.Query query = new CriteriaQuery(criteria);

            SearchHits<UserDocument> searchHits = elasticsearchOperations.search(
                    query,
                    UserDocument.class
            );

            return searchHits.stream()
                    .map(SearchHit::getContent)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("降级搜索也失败", e);
            return Collections.emptyList();
        }
    }

    /**
     * 诊断分词器状态
     */
    public void diagnoseAnalyzer() {
        try {
            // 检查索引是否存在
            boolean indexExists = elasticsearchOperations.indexOps(UserDocument.class).exists();
            log.info("索引是否存在: {}", indexExists);

            // 测试分词
            testAnalyzer("ik_max_word", "中文分词测试");
            testAnalyzer("ik_smart", "中文分词测试");
            testAnalyzer("standard", "中文分词测试");

        } catch (Exception e) {
            log.error("诊断失败", e);
        }
    }

    public void testAnalyzer(String analyzerName, String text) {
        try {
            AnalyzeRequest request = AnalyzeRequest.of(a -> a
                    .analyzer(analyzerName)
                    .text(text)
            );

            // 需要 ElasticsearchClient 来执行分析请求
            log.info("分词器 {} 测试: {}", analyzerName, "需要ElasticsearchClient");

        } catch (Exception e) {
            log.warn("分词器 {} 测试失败: {}", analyzerName, e.getMessage());
        }
    }

    /**
     * 检查索引映射
     */
    public void checkIndexMapping() {
        try {
            Map<String, Object> mapping = elasticsearchOperations.indexOps(UserDocument.class).getMapping();
            log.info("索引映射: {}", mapping);
        } catch (Exception e) {
            log.error("获取映射失败", e);
        }
    }

}